"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var neuron_1 = __importDefault(require("./neuron"));
var ReLU_1 = __importDefault(require("../../tools/ReLU"));
var diffReLU_1 = __importDefault(require("../../tools/diffReLU"));
var sigmoid_1 = __importDefault(require("../../tools/sigmoid"));
var diffSigmoid_1 = __importDefault(require("../../tools/diffSigmoid"));
var Layer = (function () {
    function Layer(shape, quant, activationFunction, neurons) {
        if (activationFunction === void 0) { activationFunction = 'none'; }
        this.neurons = [];
        this.activationFunction = undefined;
        this.derivativeOfActivationFunction = undefined;
        this.lastOut = [];
        this.shape = 0;
        this.activationFunctionName = undefined;
        this.activations = {
            'relu': { function: ReLU_1.default, derivative: diffReLU_1.default },
            'sigmoid': { function: sigmoid_1.default, derivative: diffSigmoid_1.default },
            'none': { function: undefined, derivative: undefined }
        };
        this.activationFunctionName = activationFunction;
        this.activationFunction = this.activations[activationFunction].function;
        this.derivativeOfActivationFunction = this.activations[activationFunction].derivative;
        this.shape = shape;
        if (neurons && neurons.length !== 0) {
            this.neurons = neurons;
        }
        else {
            for (var i = 0; i < quant; i++) {
                this.neurons.push(new neuron_1.default(shape));
            }
        }
    }
    Layer.prototype.feedforward = function (inputs) {
        var results = [];
        for (var _i = 0, _a = this.neurons; _i < _a.length; _i++) {
            var neuron = _a[_i];
            results.push(this.derivativeOfActivationFunction && this.activationFunction ? this.activationFunction(neuron.feedforward(inputs)) : neuron.feedforward(inputs));
        }
        this.lastOut = results;
        return results;
    };
    Layer.prototype.backward = function (inputs, derivatives) {
        var lastWeights = [];
        var newDerivatives = [];
        var derivativesOfActivationFunction = [];
        if (this.derivativeOfActivationFunction && this.activationFunction) {
            for (var _i = 0, _a = this.lastOut; _i < _a.length; _i++) {
                var out = _a[_i];
                derivativesOfActivationFunction.push(this.derivativeOfActivationFunction(out));
            }
        }
        for (var i = 0; i < this.neurons.length; i++) {
            var d = 0;
            for (var j = 0; j < derivatives.length; j++) {
                d += derivatives[j][i];
            }
            if (derivativesOfActivationFunction.length !== 0) {
                d *= derivativesOfActivationFunction[i];
            }
            lastWeights.push(this.neurons[i].backward(inputs, d));
        }
        for (var i = 0; i < lastWeights.length; i++) {
            newDerivatives[i] = [];
            for (var j = 0; j < lastWeights[i].length; j++) {
                var d = 0;
                for (var k = 0; k < derivatives.length; k++) {
                    d += derivatives[k][i];
                }
                if (derivativesOfActivationFunction.length !== 0) {
                    d *= derivativesOfActivationFunction[i];
                }
                newDerivatives[i][j] = d * lastWeights[i][j];
            }
        }
        return newDerivatives;
    };
    Layer.prototype.snapshot = function () {
        var res = { shape: this.shape, neurons: [] };
        res.activationFunction = this.activationFunctionName;
        for (var _i = 0, _a = this.neurons; _i < _a.length; _i++) {
            var neuron = _a[_i];
            res.neurons.push(neuron.snapshot());
        }
        return res;
    };
    return Layer;
}());
exports.default = Layer;
module.exports = Layer;
